#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <dirent.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>

#include "data_type.h"
#include "cube.h"
#include "cube_define.h"
#include "cube_record.h"

#include "mac_label.h"
#include "xkrnl_ctrl.h"
#include "xKrnl_policygen.h"

#define MAX_LINE_LEN 1024

static unsigned char Buf[DIGEST_SIZE*32*2];

int xKrnl_policygen_init(void * sub_proc,void * para)
{
    int ret;

    return 0;
}

int xKrnl_policygen_start(void * sub_proc,void * para)
{
    int ret = 0, len = 0, i = 0, j = 0;
    int rc = 0;

    int type,subtype;	
	BYTE local_uuid[DIGEST_SIZE];	
    ret=proc_share_data_getvalue("uuid",local_uuid);
	if(ret<0)
		return ret;
    void * recv_msg;

    while(1)
    {
        usleep(time_val.tv_usec);

		ret=ex_module_recvmsg(sub_proc,&recv_msg);
		if(ret<0)
			continue;
		if(recv_msg==NULL)
			continue;
		type=message_get_type(recv_msg);
		subtype=message_get_subtype(recv_msg);
		if(!memdb_find_recordtype(type,subtype))
		{
			printf("message format (%d %d) is not registered!\n",
			message_get_type(recv_msg),message_get_subtype(recv_msg));
			continue;
		}
		if((type==TYPE(GENERAL_RETURN))&&(subtype==SUBTYPE(GENERAL_RETURN,STRING)))
		{
			ret=proc_policy_deal(sub_proc,recv_msg);
		}
		else if((type==TYPE(XKRNL_CTRL))&&(subtype==SUBTYPE(XKRNL_CTRL,CONFIG_DATA)))
		{
			ret=proc_config_data_gen(sub_proc,recv_msg);
		}
	}
    return 0;
}

int proc_policy_deal(void * sub_proc,void * recv_msg)
{
    int ret;
	RECORD(GENERAL_RETURN,STRING) * policy_notice;

    ret = message_get_record(recv_msg,&policy_notice,0);
    if(ret<0)
        return ret;
    if(Strncmp(policy_notice->name,"policy",DIGEST_SIZE)==0)
    {
        ret = proc_output_policy(sub_proc,policy_notice,recv_msg);   
    }
    else if(Strncmp(policy_notice->name,"show config",DIGEST_SIZE)==0)
    {
        ret = proc_show_config(sub_proc,policy_notice,recv_msg);
    }

    return ret;
}


int proc_output_policy(void * sub_proc,
	RECORD(GENERAL_RETURN,STRING) * policy_notice,
    void * recv_msg)
{
    int ret;
    int i=0;
    void * record_template;
    void * record_struct;
    int fd;

    char policy_type[DIGEST_SIZE];
    char policy_path[DIGEST_SIZE*4];

    int offset=0;
    int type,subtype;

    offset = Getfiledfromstr(policy_type,policy_notice->return_value,':',DIGEST_SIZE);
    
    if(Strcmp(policy_type,"subject")==0)
    {
        type=TYPE(MAC_LABEL);    
        subtype=SUBTYPE(MAC_LABEL,SUBJECT);
        record_template = memdb_get_template(type,subtype);
    }
    else if(Strcmp(policy_type,"object")==0)
    {
        type=TYPE(MAC_LABEL);    
        subtype=SUBTYPE(MAC_LABEL,OBJECT);
        record_template = memdb_get_template(type,subtype);
    }

    fd=open(policy_notice->return_value+offset+1,O_WRONLY|O_CREAT|O_TRUNC,0666);
    if(fd<0)
        return fd;
        
    record_struct=memdb_get_first_record(type,subtype);

    while(record_struct!=NULL)
    {
        offset = struct_2_blob(record_struct,Buf,record_template);
        if(offset<0)
            return -EINVAL;
        ret=write(fd,Buf,offset);
        if(ret<0)
        {
            close(fd);
            print_cubeerr("write %s policy file failed!",policy_type); 
            return ret;
        }
        record_struct=memdb_get_next_record(type,subtype);
    }    
    close(fd);
    return 0; 
}

int proc_show_config(void * sub_proc,
	RECORD(GENERAL_RETURN,STRING) * policy_notice,
    void * recv_msg)
{
    int ret;
    int i=0;
    void * record_template;
    void * record_struct;
    int fd;

	RECORD(XKRNL_CTRL,CONFIG_DATA) * config_data;

    int offset=0;
    int type,subtype;

    // choose config data file
    if(policy_notice->return_value == NULL)
        //defalut config file
        fd=open("/boot/os_safe.d/config.cfg",O_RDONLY);
    else if(Strlen(policy_notice->return_value)<4)
        fd=open("/boot/os_safe.d/config.cfg",O_RDONLY);
    else
        // use policy_notice's return value as config file
        fd=open(policy_notice->return_value,O_RDONLY);
    if(fd<0)
        return fd;

    record_template = memdb_get_template(TYPE_PAIR(XKRNL_CTRL,
        CONFIG_DATA));
    if(record_template == NULL)
    {
        print_cubeerr("xkrnl_policygen: can't get config template");
        return -EINVAL;
    }
        
    ret=read(fd,Buf,sizeof(Buf));
    if(ret==sizeof(Buf))
        return -EINVAL;
    close(fd);    
    config_data=Talloc0(sizeof(*config_data));
    if(config_data==NULL)
        return -EINVAL;
    offset = blob_2_struct(Buf,config_data,record_template);
    if(offset<0)
        return offset;
    void * new_msg = message_create(TYPE_PAIR(XKRNL_CTRL,CONFIG_DATA),recv_msg);
    if(new_msg == NULL)
        return -EINVAL;
    message_add_record(new_msg,config_data);
    ret =ex_module_sendmsg(sub_proc,new_msg);
    return ret;
}

int proc_config_data_gen(void * sub_proc,void * recv_msg)
{
    int ret;
    int i=0;

	RECORD(XKRNL_CTRL,CONFIG_DATA) * config_data;

    ret = message_get_record(recv_msg,&config_data,0);
    if(ret<0)
        return ret;
    int fd;
    fd=open("config.cfg",O_CREAT|O_TRUNC|O_WRONLY,0666);
    if(fd<0)
        return -EINVAL;

    write(fd, config_data,sizeof(*config_data));

    close(fd);
    ret =ex_module_sendmsg(sub_proc,recv_msg);
    return ret;
}
